﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

namespace Tcp.StudyClient
{
    /// <summary>
    /// ClientByTcpClient.xaml 的交互逻辑
    /// </summary>
    public partial class ClientByTcpClient : Window
    {
        // 客户端
        TcpClient client;
        // 读写数据的流
        NetworkStream stream;

        // 是否检测服务器已关闭
        volatile bool IsCheckServerClose = false;

        public ClientByTcpClient()
        {
            InitializeComponent();
        }

        /// <summary>
        /// 连接服务器
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async void BtnConn_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                #region 用socket实现
                //client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                //// 随机生成50000到60000-1,的随机数当做客户端的端口
                //int port = new Random().Next(50000, 60000);
                //// 绑定客户端自己的ip和地址(可省略)
                //client.Bind(new IPEndPoint(IPAddress.Parse("127.0.0.1"), port));
                //await client.ConnectAsync(txtIP.Text, int.Parse(txtPort.Text));

                //AppendTxt($"连接服务器成功,我的端口号{port}", Colors.Green);

                //BtnConn.Visibility = Visibility.Collapsed;
                //BtnDisConn.Visibility = Visibility.Visible;
                #endregion

                #region 用TcpClient实现
                int port = new Random().Next(50000, 60000);
                // 设置客户端的ip和端口
                client = new TcpClient(new IPEndPoint(IPAddress.Parse("127.0.0.1"), port));
                client.Connect(IPAddress.Parse(txtIP.Text), int.Parse(txtPort.Text));

                AppendTxt($"连接服务器成功,我的端口号{port}", Colors.Green);
                BtnConn.Visibility = Visibility.Collapsed;
                BtnDisConn.Visibility = Visibility.Visible;
                #endregion

                // 获取TcpClient读写网络流
                stream = client.GetStream();
                IsCheckServerClose = false; // 刚连接成功，没有检测

                // 不停检测连接是否断开
                _ = Task.Run(async () =>
                {
                    while (true)
                    {
                        _ = Dispatcher.Invoke(async () =>
                        {
                            #region 接收信息
                            if (client != null && client.Connected)
                            {
                                // 接收的字节数组
                                byte[] recBytes = new byte[client.Available];
                                int recLen = await stream.ReadAsync(recBytes);
                                if (recLen > 0)
                                {
                                    string recStr = Encoding.UTF8.GetString(recBytes);
                                    AppendTxt($"接收信息:{recStr}", Colors.Blue);
                                }
                            }
                            #endregion

                            #region 判断断开
                            // 0、客户端自己断开/服务器断开的
                            if (client != null && !client.Connected && !IsCheckServerClose)
                            {
                                IsCheckServerClose = true; // 已经检测到了
                                AppendTxt($"连接断了", Colors.Red);
                                BtnConn.Visibility = Visibility.Visible;
                                BtnDisConn.Visibility = Visibility.Collapsed;
                                return;
                            }


                            #endregion

                        });

                        await Task.Delay(1000);
                    }
                });

            }
            catch (Exception ex)
            {
                BtnConn.Visibility = Visibility.Visible;
                BtnDisConn.Visibility = Visibility.Collapsed;
                AppendTxt($"连接服务器异常,{ex.Message}", Colors.Red);
            }
        }

        /// <summary>
        /// 断开
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void BtnDisConn_Click(object sender, RoutedEventArgs e)
        {
            if (client != null && client.Connected)
            {
                // 断开
                client.Close();

                AppendTxt($"已断开服务器", Colors.Red);

                BtnConn.Visibility = Visibility.Visible;
                BtnDisConn.Visibility = Visibility.Collapsed;
            }
        }

        /// <summary>
        /// 给服务器端发送信息
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async void BtnSend_Click(object sender, RoutedEventArgs e)
        {
            if (client != null && client.Connected)
            {
                byte[] sendBytes = Encoding.UTF8.GetBytes(txtSendContent.Text);
                // NetworkStream
                if (stream != null)
                {
                    await stream.WriteAsync(sendBytes);
                    AppendTxt($"发送信息:{txtSendContent.Text}", Colors.Black);
                }
            }
        }


        FlowDocument doc = new FlowDocument();
        /// <summary>
        /// 追加信息到richtextbox结尾
        /// </summary>
        /// <param name="txt"></param>
        /// <param name="txtColor">文字颜色</param>
        private void AppendTxt(string txt, Color txtColor)
        {
            var p = new Paragraph(); // Paragraph 类似于 html 的 P 标签
            var r = new Run($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} {txt}"); // Run 是一个 Inline 的标签
            p.Inlines.Add(r);
            p.Foreground = new SolidColorBrush(txtColor);//设置字体颜色
            doc.Blocks.Add(p);
            txtShowContent.Document = doc;
            txtShowContent.ScrollToEnd();
        }
    }
}
